package com.gzx.plugin.tjzy.modular.call.ht.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gzx.plugin.tjzy.core.utils.crypter.HtCrypterDecrypt;
import com.gzx.plugin.tjzy.modular.call.ht.entity.GzxHtCallRecord;
import com.gzx.plugin.tjzy.modular.call.ht.entity.GzxHtUser;
import com.gzx.plugin.tjzy.modular.call.ht.entity.GzxHtVoiceText;
import com.gzx.plugin.tjzy.modular.call.ht.entity.GzxSyncCallRecord;
import com.gzx.plugin.tjzy.modular.call.ht.entity.bo.GzxCallReportBo;
import com.gzx.plugin.tjzy.modular.call.ht.entity.bo.GzxHtCallRecordQueryBo;
import com.gzx.plugin.tjzy.modular.call.ht.entity.bo.GzxSyncHtCallRecordBo;
import com.gzx.plugin.tjzy.modular.call.ht.entity.vo.GzxCallReportVo;
import com.gzx.plugin.tjzy.modular.call.ht.entity.vo.GzxHtCallRecordVo;
import com.gzx.plugin.tjzy.modular.call.ht.mapper.GzxHtCallRecordMapper;
import com.gzx.plugin.tjzy.modular.call.ht.mapper.GzxHtUserMapper;
import com.gzx.plugin.tjzy.modular.call.ht.mapper.GzxSyncCallRecordMapper;
import com.gzx.plugin.tjzy.modular.call.ht.service.GzxHtCallRecordService;
import com.gzx.plugin.tjzy.modular.call.pre.template.HtPreCallTemplateMethod;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.cache.CommonCacheOperator;
import vip.xiaonuo.common.consts.IntConstant;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.kafka.KafkaMessageProducer;
import vip.xiaonuo.common.kafka.KafkaTopicConstant;
import vip.xiaonuo.common.sses.entity.SseMessage;
import vip.xiaonuo.common.sses.util.CommonSseUtil;
import vip.xiaonuo.common.tenant.TenantContext;
import vip.xiaonuo.common.util.CommonCalculateUtil;
import vip.xiaonuo.common.util.CommonCryptogramUtil;
import vip.xiaonuo.common.util.CommonDateUtil;
import vip.xiaonuo.common.util.CommonExcelUtil;
import vip.xiaonuo.sys.api.SysUserApi;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zjt
 * @description
 * @date 2024/12/4 17:35
 */
@Slf4j
@Service
@DS("tjzy-async")
@RequiredArgsConstructor
public class GzxHtCallRecordServiceImpl extends HtPreCallTemplateMethod implements GzxHtCallRecordService {

    private final GzxHtCallRecordMapper htCallRecordMapper;

    private final GzxHtUserMapper htUserMapper;

    private final CommonCacheOperator cacheOperator;

    private final GzxSyncCallRecordMapper syncCallRecordMapper;

    private final SysUserApi sysUserFeign;

    private final KafkaMessageProducer kafkaMessageProducer;

    private final CommonSseUtil sseUtil;

    /**
     * 保存恒天回传的话单数据
     *
     * @param callRecordStr
     */
    @Override
    public void saveHtCallRecord(String callRecordStr) {
        log.info("恒天话单回调数据：{}", callRecordStr);
        //恒天话单字符串转对象
        GzxHtCallRecord htCallRecord = JSON.parseObject(callRecordStr, GzxHtCallRecord.class);
        String callId = cacheOperator.getCatchString(htCallRecord.getCallId());
        if (StringUtils.isNotEmpty(callId)) {
            return;
        }
        kafkaMessageProducer.sendMessage(KafkaTopicConstant.EVENT_TOPIC, htCallRecord.getCallId(), JSON.toJSONString(htCallRecord));
        cacheOperator.setCatchString(htCallRecord.getCallId(), callId, 3600);
    }

    /**
     * 批量保存话单记录
     *
     * @param htCallRecordList
     */
    @Override
    public void asyncInsertRecord(List<GzxHtCallRecord> htCallRecordList) {
        //批量插入话单记录
        htCallRecordMapper.insertBatch(htCallRecordList);
    }

    /**
     * 同步自定义时间内的恒天话单
     */
    @Override
    public void syncCallRecordCustomerTime() {
        long startTime = System.currentTimeMillis();
        int offset = 0; // 起始值
        int totalRecords = 0; // 总记录数
        int totalProcessed = 0; // 已处理的记录总数
        GzxSyncCallRecord syncCallRecord = syncCallRecordMapper.selectOne(Wrappers.<GzxSyncCallRecord>lambdaQuery()
                .orderByDesc(GzxSyncCallRecord::getId)
                .last("limit 1"));
        String currentTime = syncCallRecord.getCurrentTime();
        if (CommonDateUtil.isAfterMinutes(currentTime, -30)) {
            do {
                String jsonData = getCallRecord(CommonDateUtil.getTimeBeforeOrAfterMinutes(currentTime, -1), currentTime, offset);
                log.info("话单补偿：恒天本次返回数据：{}", jsonData);
                totalRecords = com.alibaba.fastjson2.JSONObject.parseObject(jsonData).getIntValue("count");
                log.info("话单补偿：恒天本次返回数量{}", totalRecords);
                if (totalRecords > 0) {
                    // 获取当前批次的数据
                    List<GzxSyncHtCallRecordBo> syncHtCallRecordBoList = JSON.parseArray(com.alibaba.fastjson2.JSONObject.parseObject(jsonData).getString("data"), GzxSyncHtCallRecordBo.class);
                    if (CollectionUtil.isNotEmpty(syncHtCallRecordBoList)) {
                        List<String> callIdList = new ArrayList<>(syncHtCallRecordBoList.stream().map(GzxSyncHtCallRecordBo::getCallId).toList());
                        //根据CallId查询话单记录
                        try {
                            TenantContext.disableTenantFilter();
                            long htCallRecordDataSourceStartTime = System.currentTimeMillis();
                            List<GzxHtCallRecord> htCallRecordList = htCallRecordMapper.selectList(Wrappers.<GzxHtCallRecord>lambdaQuery()
                                    .in(GzxHtCallRecord::getCallId, callIdList));
                            log.info("话单补偿：本次查询恒天话单表耗时{},CallId数量:{}", System.currentTimeMillis() - htCallRecordDataSourceStartTime, callIdList.size());
                            List<String> dataSource = htCallRecordList.stream().map(GzxHtCallRecord::getCallId).toList();
                            callIdList.removeAll(dataSource);
                            List<GzxSyncHtCallRecordBo> noCallRecordList = syncHtCallRecordBoList.stream().filter(s -> callIdList.contains(s.getCallId())).toList();
                            List<GzxHtCallRecord> noDataSourceHtCallRecordList = buildCallRecord(noCallRecordList);
                            if (CollectionUtil.isNotEmpty(noDataSourceHtCallRecordList)) {
                                log.info("本次话单补偿数量：{}", noDataSourceHtCallRecordList.size());
                                log.info("本次话单补偿集合：{}", JSON.toJSONString(noDataSourceHtCallRecordList));
                                noDataSourceHtCallRecordList.forEach(s -> {
                                    s.setCallee(HtCrypterDecrypt.decrypt(s.getCallee()));
                                    kafkaMessageProducer.sendMessage("event-topic", s.getCallId(), JSON.toJSONString(s));
                                    cacheOperator.setCatchString(s.getCallId(), s.getCallId(), 3600);
                                });
                            }
                            syncCallRecord.setSize(noDataSourceHtCallRecordList.size());
                            syncCallRecordMapper.updateById(syncCallRecord);
                        } catch (Exception e) {
                            log.error("话单补偿出现异常：{}", e.getMessage());
                        } finally {
                            TenantContext.enableTenantFilter();
                            TenantContext.clear();
                        }
                    }
                    // 更新已处理的记录总数
                    totalProcessed += syncHtCallRecordBoList.size();
                    // 更新 offset 为下一批次的起始值
                    offset += 1000;
                }
                // 判断是否需要继续分页
            } while (totalProcessed < totalRecords);
            //时间+1保存到数据库
            syncCallRecordMapper.insert(new GzxSyncCallRecord(CommonDateUtil.getTimeBeforeOrAfterMinutes(currentTime, 1)));
            log.info("话单补偿结束，耗时：{}", System.currentTimeMillis() - startTime);
        }
    }

    /**
     * 同步最近的恒天话单
     */
    @Override
    public void syncCallRecordLast() {
        long startTime = System.currentTimeMillis();
        int offset = 0; // 起始值
        int totalRecords = 0; // 总记录数
        int totalProcessed = 0; // 已处理的记录总数
        String currentTime = CommonDateUtil.getCurrentTimeStr();
        do {
            String jsonData = getCallRecord(CommonDateUtil.getTimeBeforeOrAfterMinutes(currentTime, -17), CommonDateUtil.getTimeBeforeOrAfterMinutes(currentTime, -2), offset);
            log.info("话单补偿：恒天本次返回数据：{}", jsonData);
            totalRecords = com.alibaba.fastjson2.JSONObject.parseObject(jsonData).getIntValue("count");
            log.info("话单补偿：恒天本次返回数量{}", totalRecords);
            if (totalRecords > 0) {
                // 获取当前批次的数据
                List<GzxSyncHtCallRecordBo> syncHtCallRecordBoList = JSON.parseArray(com.alibaba.fastjson2.JSONObject.parseObject(jsonData).getString("data"), GzxSyncHtCallRecordBo.class);
                if (CollectionUtil.isNotEmpty(syncHtCallRecordBoList)) {
                    List<String> callIdList = new ArrayList<>(syncHtCallRecordBoList.stream().map(GzxSyncHtCallRecordBo::getCallId).toList());
                    //根据CallId查询话单记录
                    try {
                        TenantContext.disableTenantFilter();
                        long htCallRecordDataSourceStartTime = System.currentTimeMillis();
                        List<GzxHtCallRecord> htCallRecordList = htCallRecordMapper.selectList(Wrappers.<GzxHtCallRecord>lambdaQuery()
                                .in(GzxHtCallRecord::getCallId, callIdList));
                        log.info("话单补偿：本次查询恒天话单表耗时{},CallId数量:{}", System.currentTimeMillis() - htCallRecordDataSourceStartTime, callIdList.size());
                        List<String> dataSource = htCallRecordList.stream().map(GzxHtCallRecord::getCallId).toList();
                        callIdList.removeAll(dataSource);
                        List<GzxSyncHtCallRecordBo> noCallRecordList = syncHtCallRecordBoList.stream().filter(s -> callIdList.contains(s.getCallId())).toList();
                        List<GzxHtCallRecord> noDataSourceHtCallRecordList = buildCallRecord(noCallRecordList);
                        if (CollectionUtil.isNotEmpty(noDataSourceHtCallRecordList)) {
                            log.info("本次话单补偿数量：{}", noDataSourceHtCallRecordList.size());
                            log.info("本次话单补偿集合：{}", JSON.toJSONString(noDataSourceHtCallRecordList));
                            noDataSourceHtCallRecordList.forEach(s -> {
                                if (cacheOperator.setIfAbsent(s.getCallId(), s.getCallId(), 3600)) {
                                    s.setCallee(HtCrypterDecrypt.decrypt(s.getCallee()));
                                    if (s.getCallType() == 9) {
                                        s.setCallType(1);
                                    }
                                    kafkaMessageProducer.sendMessage("event-topic", s.getCallId(), JSON.toJSONString(s));
                                    cacheOperator.setCatchString(s.getCallId(), s.getCallId(), 3600);
                                }
                            });
                        }
                    } catch (Exception e) {
                        log.error("话单补偿出现异常：{}", e.getMessage());
                    } finally {
                        TenantContext.enableTenantFilter();
                        TenantContext.clear();
                    }
                }
                // 更新已处理的记录总数
                totalProcessed += syncHtCallRecordBoList.size();
                // 更新 offset 为下一批次的起始值
                offset += 1000;
            }
            // 判断是否需要继续分页
        } while (totalProcessed < totalRecords);
        log.info("话单补偿结束，本次耗时：{}", System.currentTimeMillis() - startTime);
    }

    /**
     * 同步恒天话单
     */
    @Override
    public void syncCallRecord() {

    }

    /**
     * 分页查询话单记录
     *
     * @param htCallRecordQueryBo
     * @return
     */
    @Override
    public Page<GzxHtCallRecordVo> pageList(GzxHtCallRecordQueryBo htCallRecordQueryBo) {
        return htCallRecordMapper.selectVoPage(new Page<>(htCallRecordQueryBo.getCurrent(), htCallRecordQueryBo.getSize()), Wrappers.<GzxHtCallRecord>lambdaQuery()
                .eq(htCallRecordQueryBo.getCaseId() != null, GzxHtCallRecord::getCaseId, htCallRecordQueryBo.getCaseId())
                .eq(StringUtils.isNotEmpty(htCallRecordQueryBo.getCallId()), GzxHtCallRecord::getCallId, htCallRecordQueryBo.getCallId())
                .between(htCallRecordQueryBo.getCaseId() == null, GzxHtCallRecord::getCreatedTime, htCallRecordQueryBo.getBeginTime(), htCallRecordQueryBo.getEndTime())
                .eq(StringUtils.isNotBlank(htCallRecordQueryBo.getCaller()), GzxHtCallRecord::getCaller, htCallRecordQueryBo.getCaller())
                .eq(StringUtils.isNotBlank(htCallRecordQueryBo.getCallee()), GzxHtCallRecord::getCallee, CommonCryptogramUtil.doSm1AesEncrypt(htCallRecordQueryBo.getCallee()))
                .eq(StringUtils.isNotBlank(htCallRecordQueryBo.getUserName()), GzxHtCallRecord::getAgentNum, htCallRecordQueryBo.getUserName())
                .gt(htCallRecordQueryBo.getCallDuration() != null, GzxHtCallRecord::getCallDuration, htCallRecordQueryBo.getCallDuration())
                .eq(StringUtils.isNotBlank(htCallRecordQueryBo.getCallType()), GzxHtCallRecord::getCallType, htCallRecordQueryBo.getCallType())
                .eq(StringUtils.isNotBlank(htCallRecordQueryBo.getDeptId()), GzxHtCallRecord::getDeptId, htCallRecordQueryBo.getDeptId())
                .orderByDesc(GzxHtCallRecord::getId));
    }

    /**
     * 获取当前登录用户的恒天账号
     *
     * @return
     */
    @Override
    public String getHtAccount() {
        GzxHtUser htUser = htUserMapper.selectOne(Wrappers.<GzxHtUser>lambdaQuery()
                .eq(GzxHtUser::getUserName, StpLoginUserUtil.getLoginUser().getAccount()));
        if (htUser == null) {
            return StpLoginUserUtil.getLoginUser().getAccount();
        }
        return htUser.getHtAccount();
    }

    @Override
    public void setFmPhone(String fmPhone) {
        cacheOperator.setCatchString("FM_PHONE", fmPhone);
    }

    /**
     * 设置主叫号码
     *
     * @param callNumber
     */
    @Override
    public void setCallNumber(String callNumber) {
        cacheOperator.setCatchString("CallNumber_" + StpLoginUserUtil.getLoginUser().getId(), callNumber);
    }

    /**
     * 获取当前坐席的主叫号码
     *
     * @return
     */
    @Override
    public String getCallNumber() {
        return cacheOperator.getCatchString("CallNumber_" + StpLoginUserUtil.getLoginUser().getId());
    }

    /**
     * 根据CallId保存当前登录者信息
     *
     * @param callId
     */
    @Override
    public void setCallUser(String callId) {
        cacheOperator.setCatchString("CallId_" + callId, StpLoginUserUtil.getLoginUser().getId(), 1800);
    }

    /**
     * 发送消息
     */
    @Override
    public void sendMessage() {
        GzxHtVoiceText htVoiceText = new GzxHtVoiceText();
        htVoiceText.setChatTime(CommonDateUtil.getCurrentTimeStr());
        int random = (int) (Math.random() * 2) + 1;
        htVoiceText.setSpeakerRole(random);
        htVoiceText.setCallId("20250218111641012934400277");
        String text = generateRandomChineseString((int) (Math.random() * 20) * 50);
        if (random == 1) {
            htVoiceText.setContent("我是客户:" + getKeyword() + text);
        }
        if (random == 2) {
            htVoiceText.setContent("我是坐席:" + text);
        }
        receiveVoiceText(JSON.toJSONString(htVoiceText));
    }

    /**
     * 接收语音转文字的对象
     *
     * @param reqBody
     */
    @Override
    public void receiveVoiceText(String reqBody) {
        log.info("收到恒天回传的语音文字：{}", reqBody);
        GzxHtVoiceText htVoiceText = JSON.parseObject(reqBody, GzxHtVoiceText.class);
        if (htVoiceText != null) {
            htVoiceText.setContent(htVoiceText.getContent().replaceAll("\\s", ""));
            //发送到消息队列
            kafkaMessageProducer.sendMessage("voice-topic", htVoiceText.getCallId() + "|" + htVoiceText.getSessionNo(), JSON.toJSONString(htVoiceText));
            if (StringUtils.isNotEmpty(htVoiceText.getCallId())) {
                //去redis获取对应的LoginId
                String loginId = getLoginIdByCallIdFromCache(htVoiceText.getCallId());
                if (StringUtils.isNotEmpty(loginId)) {
                    sseUtil.sendMessageToUser(loginId, new SseMessage("", JSON.toJSONString(htVoiceText)));
                }
            }
        }
    }

    /**
     * 获取坐席工作报表
     *
     * @param bo
     * @return
     */
    @Override
    public Page<GzxCallReportVo> pageCallReport(GzxCallReportBo bo) {
        if (StringUtils.isEmpty(bo.getDeptId()) || StringUtils.isEmpty(bo.getCreateDate())) {
            throw new CommonException("时间和部门都不允许为空");
        }
        Page<GzxCallReportVo> callReportVoPage = htCallRecordMapper.pageCallReport(new Page<>(bo.getCurrent(), bo.getSize()), bo.getCreateDate(), bo.getDeptId());
        if (CollectionUtil.isNotEmpty(callReportVoPage.getRecords())) {
            setCallReport(callReportVoPage.getRecords());
        }
        return callReportVoPage;
    }

    /**
     * 导出数据
     *
     * @param bo
     * @return
     */
    @Override
    public void exportCallReport(GzxCallReportBo bo, HttpServletResponse response) {
        if (StringUtils.isEmpty(bo.getDeptId()) || StringUtils.isEmpty(bo.getCreateDate())) {
            throw new CommonException("时间和部门都不允许为空");
        }
        List<GzxCallReportVo> callReportVoList = htCallRecordMapper.pageCallReport(new Page<>(1, IntConstant.VALUE_200), bo.getCreateDate(), bo.getDeptId()).getRecords();
        if (CollectionUtil.isNotEmpty(callReportVoList)) {
            setCallReport(callReportVoList);
            CommonExcelUtil.exportExcel(callReportVoList.getFirst().getDeptName(), callReportVoList, GzxCallReportVo.class, response);
        } else {
            throw new CommonException("无可导出的数据");
        }
    }

    private String generateRandomChineseString(int length) {
        StringBuilder sb = new StringBuilder(length);
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            int codePoint = 0x4E00 + random.nextInt(0x9FA5 - 0x4E00 + 1);
            sb.append(Character.toChars(codePoint));
        }
        return sb.toString();
    }

    private String getKeyword() {
        String[] array = {" ", "跳楼", "跳河", "喝药", "不想活"};
//        String[] array = {"投诉", "自杀", "举报", " ", "报警", "拉黑","跳楼","",""};
        // 创建Random对象
        Random random = new Random();
        // 生成一个随机索引
        int randomIndex = random.nextInt(array.length);
        return array[randomIndex];
    }

    /**
     * 获取预测外呼参数，Key为手机号，val为透传字段
     *
     * @param batchNumber
     * @return
     */
    @Override
    protected Map<String, Long> getCallParams(String batchNumber) {
        return Map.of();
    }

    /**
     * 保存任务ID
     *
     * @param taskId
     * @param idList
     */
    @Override
    protected void saveTaskId(String taskId, List<Long> idList) {

    }

    private String getLoginIdByCallIdFromCache(String callId) {
        String loginId = null;
        for (int i = 0; i <= 5; i++) {
            if (cacheOperator.isKeyExists("CallId_" + callId)) {
                loginId = cacheOperator.getCatchString("CallId_" + callId);
                break;
            } else {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                }
            }
        }
        return loginId;
    }

    private List<GzxHtCallRecord> buildCallRecord(List<GzxSyncHtCallRecordBo> syncHtCallRecordBoList) {
        List<GzxHtCallRecord> htCallRecordList = new ArrayList<>();
        for (GzxSyncHtCallRecordBo syncHtCallRecordBo : syncHtCallRecordBoList) {
            GzxHtCallRecord htCallRecord = new GzxHtCallRecord();
            BeanUtils.copyProperties(syncHtCallRecordBo, htCallRecord);
            htCallRecord.setCallType(syncHtCallRecordBo.getTaskType());
            htCallRecord.setCaller(syncHtCallRecordBo.getCallPhone());
            htCallRecord.setRingDuration(syncHtCallRecordBo.getRingTime());
            htCallRecord.setFileUrl(syncHtCallRecordBo.getFileName());
            htCallRecord.setArea(syncHtCallRecordBo.getAreaCode());
            htCallRecord.setResult(String.valueOf(syncHtCallRecordBo.getDialSucc()));
            htCallRecordList.add(htCallRecord);
        }
        return htCallRecordList;
    }

    private void setCallReport(List<GzxCallReportVo> callReportVoList) {
        Set<String> accountSet = callReportVoList.stream().map(GzxCallReportVo::getAgentNum).collect(Collectors.toSet());
        List<cn.hutool.json.JSONObject> userList = sysUserFeign.getUserByAccount(accountSet);
        Map<String, cn.hutool.json.JSONObject> userMap = new HashMap<>();
        for (cn.hutool.json.JSONObject str : userList) {
            userMap.put(str.getStr("account"), str);
        }
        for (GzxCallReportVo callReportVo : callReportVoList) {
            callReportVo.setInfo(callReportVo.getConnectCalls() + "/" + callReportVo.getTotalCalls());
            callReportVo.setConnRate(CommonCalculateUtil.calculatePercentage(callReportVo.getConnectCalls(), callReportVo.getTotalCalls()));
            callReportVo.setNoValidConnected(callReportVo.getConnectCalls() - callReportVo.getValidConnected());
            callReportVo.setValidConnectRate(CommonCalculateUtil.calculatePercentage(callReportVo.getValidConnected(), callReportVo.getTotalCalls()));
            cn.hutool.json.JSONObject jsonObject = userMap.get(callReportVo.getAgentNum());
            if (jsonObject != null) {
                callReportVo.setUserName(userMap.get(callReportVo.getAgentNum()).getStr("name"));
                callReportVo.setDeptName(userMap.get(callReportVo.getAgentNum()).getStr("orgName"));
            } else {
                callReportVo.setUserName("呼入");
            }
        }
    }
}
